package models;

import java.util.LinkedList;
import java.util.List;

import javax.persistence.*;

import play.db.jpa.Model;

@Entity
@Table(name = "Task_Types")
public class TaskType extends Model {
	public String type;

	@OneToMany(mappedBy = "type")
	public List<Task> tasks = new LinkedList<Task>();

	@ManyToOne
	public Project project;

	@OneToMany(mappedBy = "taskType", cascade = { CascadeType.REMOVE })
	public List<ComponentTaskTypeUser> taskTypeReviewers = new LinkedList<ComponentTaskTypeUser>();

	public boolean isSystem;

	/**
	 * constructs a new TaskType
	 * 
	 * @param name
	 * @param isSystem
	 */
	public TaskType(String name, boolean isSystem) {
		this.isSystem = isSystem;
		this.type = name;
	}

	public TaskType(String name, Project project) {
		this.isSystem = false;
		this.type = name;
		this.project = project;
	}

	public TaskType(String type) {
		this.type = type;
	}

	/**
	 * changes the name of a TaskType
	 * 
	 * @param newName
	 */
	public void changeName(String newName) {
		this.type = newName;
		save();
	}

	public TaskType delete() {
		for (Task task : tasks) {
			task.type = null;
			task.save();
		}
		return super.delete();
	}

	/**
	 * This method gets a list of all Task Types in the system
	 * 
	 * @return List<TaskType>
	 */
	public static List<TaskType> getAllTaskTypes() {
		List<TaskType> allTaskTypes = TaskType.all().fetch();

		int i = 0;
		while (i < allTaskTypes.size()) {
			if (allTaskTypes.get(i).isSystem == false)
				allTaskTypes.remove(allTaskTypes.get(i));
			else
				i++;
		}

		return allTaskTypes;
	}

	/**
	 * Deletes all the requests to review a certain task type within a component
	 * once the request to review that task type for the whole project is
	 * accepted.
	 * 
	 * @param reviewerId
	 *            The id of the reviewer who sent the request.
	 * @param typeId
	 *            The id of the task type to be reviewed.
	 * @param projectId
	 *            The id of the project.
	 * @param allRequests
	 *            The list of all the requests in the system.
	 * @return boolean
	 * @author Rawan
	 */
	public boolean deleteComponentReviewRequests(final long reviewerId,
			final long projectId, final List<ComponentTaskTypeUser> allRequests) {
		for (int i = 0; i < allRequests.size(); i++) {
			if (allRequests.get(i).reviewer.getEntityId().equals(reviewerId)
					&& allRequests.get(i).taskType.getEntityId().equals(
							this.getEntityId())
					&& allRequests.get(i).component.project.getEntityId()
							.equals(projectId)
					&& !allRequests.get(i).component.name
							.equalsIgnoreCase("default component")) {
				new Log(
						(Long) allRequests.get(i).getEntityId(),
						"ComponentTaskTypeUser",
						"Removed pending review requests by \""
								+ allRequests.get(i).reviewer.userName
								+ "\" for the task type \""
								+ allRequests.get(i).taskType.type
								+ "\" for the component \""
								+ allRequests.get(i).component.name
								+ "\" for the project \""
								+ allRequests.get(i).component.project.name
								+ "\" because the request for that user to review the "
								+ "task type for the whole project has been accepted.",
						projectId, "").save();
				allRequests.get(i).delete();
			}
		}
		return true;
	}

	/**
	 * Returns a list of all the users who have been approved to review a
	 * specific task type for a specific component. If the component is null,
	 * then the users are those who are approved to review the task type for the
	 * whole project.
	 * 
	 * @param type
	 *            The task type the users are reviewing.
	 * @param component
	 *            The component for which the users are reviewing the type.
	 * @return List<User>
	 */
	public List<User> getTaskTypeReviewers(Component component) {
		List<User> reviewers = new LinkedList<User>();
		List<ComponentTaskTypeUser> acceptedRequests = this
				.getAcceptedRequests(this.project, component);
		for (int i = 0; i < acceptedRequests.size(); i++) {
			reviewers.add(acceptedRequests.get(i).reviewer);
		}
		return reviewers;
	}

	/**
	 * Retrieves all the requests that have been accepted for a specific task
	 * type within a certain project whether this request is for a specific
	 * component or the whole project.
	 * 
	 * @param type
	 *            The task type to retrieve the requests for.
	 * @param project
	 *            The project in which the task type exists.
	 * @return List<ComponentTaskTypeUser>
	 */
	public List<ComponentTaskTypeUser> getAcceptedRequests(Project project,
			Component component) {
		List<ComponentTaskTypeUser> acceptedRequests = new LinkedList<ComponentTaskTypeUser>();
		List<ComponentTaskTypeUser> allRequests = ComponentTaskTypeUser.all()
				.fetch();
		if (component != null) {
			for (int i = 0; i < allRequests.size(); i++) {
				if (allRequests.get(i).taskType.type.equals(this.type)
						&& allRequests.get(i).component.project.name
								.equals(project.name)
						&& allRequests.get(i).component.name
								.equals(component.name)
						&& allRequests.get(i).status) {
					acceptedRequests.add(allRequests.get(i));
				}
			}
		} else {
			for (int i = 0; i < allRequests.size(); i++) {
				if (allRequests.get(i).taskType.type.equals(this.type)
						&& allRequests.get(i).component.project.name
								.equals(project.name)
						&& allRequests.get(i).component.name
								.equalsIgnoreCase("default component")
						&& allRequests.get(i).status) {
					acceptedRequests.add(allRequests.get(i));
				}
			}
		}
		return acceptedRequests;
	}

}
